using DocumentCreationSystem.Models;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace DocumentCreationSystem.Services;

/// <summary>
/// LM Studio服务实现
/// </summary>
public class LMStudioService : IAIService
{
    private readonly IConfiguration _configuration;
    private readonly ILogger _logger;
    private readonly HttpClient _httpClient;
    private readonly string _baseUrl;
    private readonly List<AIModel> _availableModels;
    private AIModel? _currentModel;

    public LMStudioService(IConfiguration configuration, ILogger logger)
    {
        _configuration = configuration;
        _logger = logger;

        // 创建HttpClientHandler并配置SSL（虽然LM Studio通常使用HTTP，但为了一致性）
        var handler = new HttpClientHandler();

        // 配置SSL证书验证
        handler.ServerCertificateCustomValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
        {
            if (sslPolicyErrors == System.Net.Security.SslPolicyErrors.None)
                return true;

            _logger.LogWarning($"LM Studio SSL证书验证警告: {sslPolicyErrors}");
            return true; // 暂时允许所有证书，解决SSL连接问题
        };

        _httpClient = new HttpClient(handler);

        _baseUrl = configuration["BaseUrl"] ?? "http://50844s9656.wocp.fun:42440";
        _availableModels = new List<AIModel>();

        ConfigureHttpClient();
        _ = Task.Run(async () =>
        {
            // 首先检查服务是否可用
            if (await IsServiceAvailableAsync())
            {
                await LoadAvailableModelsAsync();
                await DetectAndSetCurrentModelAsync();
            }
            else
            {
                _logger.LogInformation("LM Studio服务暂时不可用，将在需要时重试连接");
            }
        });
    }

    private void ConfigureHttpClient()
    {
        _httpClient.DefaultRequestHeaders.Add("User-Agent", "DocumentCreationSystem/1.0");
        // 设置标准API超时时间
        _httpClient.Timeout = TimeSpan.FromSeconds(120); // 120秒，符合API请求最佳实践
    }

    /// <summary>
    /// 检查LM Studio服务是否可用
    /// </summary>
    private async Task<bool> IsServiceAvailableAsync()
    {
        try
        {
            using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
            var response = await _httpClient.GetAsync($"{_baseUrl}/v1/models", cts.Token);
            return response.IsSuccessStatusCode;
        }
        catch (TaskCanceledException)
        {
            _logger.LogDebug("LM Studio服务连接超时");
            return false;
        }
        catch (HttpRequestException ex)
        {
            _logger.LogDebug($"LM Studio服务连接失败: {ex.Message}");
            return false;
        }
        catch (Exception ex)
        {
            _logger.LogDebug(ex, "检查LM Studio服务可用性时发生错误");
            return false;
        }
    }

    private async Task LoadAvailableModelsAsync()
    {
        try
        {
            _logger.LogInformation($"开始从LM Studio加载模型列表: {_baseUrl}");

            // 设置较短的超时时间用于模型列表获取
            using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(15));
            var response = await _httpClient.GetAsync($"{_baseUrl}/v1/models", cts.Token);

            if (response.IsSuccessStatusCode)
            {
                var json = await response.Content.ReadAsStringAsync();
                _logger.LogDebug($"LM Studio API响应: {json}");

                // 使用正确的JSON序列化选项
                var options = new JsonSerializerOptions
                {
                    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
                    PropertyNameCaseInsensitive = true
                };

                // 直接解析JSON，因为LMStudioModelsResponse在其他文件中定义
                using var document = JsonDocument.Parse(json);
                var root = document.RootElement;

                if (root.TryGetProperty("data", out var dataElement))
                {
                    _availableModels.Clear();
                    foreach (var modelElement in dataElement.EnumerateArray())
                    {
                        var modelId = modelElement.GetProperty("id").GetString() ?? "";
                        if (!string.IsNullOrEmpty(modelId))
                        {
                            _availableModels.Add(new AIModel
                            {
                                Id = modelId,
                                Name = modelId,
                                Provider = "LMStudio",
                                Description = $"LM Studio本地模型 - {modelId}",
                                IsAvailable = true,
                                MaxTokens = GetModelMaxTokens(modelId) // 根据模型类型设置合适的token限制
                            });
                        }
                    }

                    if (_availableModels.Any())
                    {
                        _logger.LogInformation($"LM Studio成功加载了 {_availableModels.Count} 个模型");
                        foreach (var model in _availableModels)
                        {
                            _logger.LogInformation($"  - {model.Id}");
                        }
                    }
                    else
                    {
                        _logger.LogInformation("LM Studio连接成功，但没有发现可用模型。请在LM Studio中加载模型。");
                    }
                }
                else
                {
                    _logger.LogInformation("LM Studio API响应中没有data字段，可能没有加载模型");
                }
            }
            else
            {
                var errorContent = await response.Content.ReadAsStringAsync();
                _logger.LogInformation($"LM Studio API请求失败，状态码: {response.StatusCode}，响应: {errorContent}");
            }
        }
        catch (TaskCanceledException)
        {
            _logger.LogInformation("连接LM Studio超时，请检查LM Studio是否正在运行");
        }
        catch (HttpRequestException ex)
        {
            _logger.LogInformation($"无法连接到LM Studio服务: {ex.Message}");
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "加载LM Studio模型列表时发生错误");
        }
    }

    /// <summary>
    /// 检测并设置当前加载的模型
    /// </summary>
    private async Task DetectAndSetCurrentModelAsync()
    {
        try
        {
            // 首先检查是否有可用模型
            if (!_availableModels.Any())
            {
                _logger.LogInformation("没有可用模型，跳过当前模型检测");
                return;
            }

            _logger.LogInformation("开始检测LM Studio当前加载的模型...");

            // 尝试通过聊天完成API检测当前模型
            var currentModel = await DetectCurrentLoadedModelAsync();

            if (currentModel != null)
            {
                _currentModel = currentModel;
                _logger.LogInformation($"检测到当前加载的模型: {_currentModel.Id}");
            }
            else
            {
                // 如果无法检测到当前模型，使用第一个可用模型
                _currentModel = _availableModels.First();
                _logger.LogInformation($"无法检测当前模型，使用第一个可用模型: {_currentModel.Id}");
            }
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "检测当前加载模型失败");

            // 如果检测失败，使用第一个可用模型作为备选
            if (_availableModels.Any())
            {
                _currentModel = _availableModels.First();
                _logger.LogInformation($"检测失败，使用备选模型: {_currentModel.Id}");
            }
            else
            {
                _logger.LogInformation("没有可用模型，无法设置当前模型");
            }
        }
    }

    /// <summary>
    /// 通过API调用检测当前加载的模型
    /// </summary>
    private async Task<AIModel?> DetectCurrentLoadedModelAsync()
    {
        try
        {
            var url = $"{_baseUrl.TrimEnd('/')}/v1/chat/completions";

            var requestBody = new
            {
                model = "auto", // 使用auto让LM Studio自动选择当前加载的模型
                messages = new[]
                {
                    new { role = "user", content = "test" }
                },
                max_tokens = 1,
                temperature = 0.1
            };

            var json = JsonSerializer.Serialize(requestBody);
            var content = new StringContent(json, Encoding.UTF8, "application/json");

            // 设置较短的超时时间用于检测
            using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
            var response = await _httpClient.PostAsync(url, content, cts.Token);

            if (response.IsSuccessStatusCode)
            {
                var responseContent = await response.Content.ReadAsStringAsync();
                var responseJson = JsonDocument.Parse(responseContent);

                // 尝试从响应中获取模型信息
                if (responseJson.RootElement.TryGetProperty("model", out var modelElement))
                {
                    var modelId = modelElement.GetString();
                    if (!string.IsNullOrEmpty(modelId))
                    {
                        // 在可用模型列表中查找匹配的模型
                        var matchedModel = _availableModels.FirstOrDefault(m =>
                            m.Id.Equals(modelId, StringComparison.OrdinalIgnoreCase) ||
                            m.Id.Contains(modelId, StringComparison.OrdinalIgnoreCase));

                        if (matchedModel != null)
                        {
                            _logger.LogInformation($"通过API检测到当前模型: {modelId}");
                            return matchedModel;
                        }
                        else
                        {
                            // 如果在列表中找不到，创建一个新的模型对象
                            var detectedModel = new AIModel
                            {
                                Id = modelId,
                                Name = modelId,
                                Provider = "LMStudio",
                                Description = $"LM Studio当前加载的模型 - {modelId}",
                                IsAvailable = true,
                                MaxTokens = GetModelMaxTokens(modelId)
                            };

                            // 添加到可用模型列表
                            _availableModels.Add(detectedModel);
                            _logger.LogInformation($"检测到新模型并添加到列表: {modelId}");
                            return detectedModel;
                        }
                    }
                }
            }
            else
            {
                var errorContent = await response.Content.ReadAsStringAsync();
                if (response.StatusCode == System.Net.HttpStatusCode.BadGateway)
                {
                    _logger.LogInformation("LM Studio可能没有加载模型或服务未完全启动，跳过当前模型检测");
                }
                else
                {
                    _logger.LogInformation($"检测当前模型失败，HTTP状态码: {response.StatusCode}，响应: {errorContent}");
                }
            }
        }
        catch (TaskCanceledException)
        {
            _logger.LogInformation("检测当前模型超时，LM Studio可能正在启动或没有加载模型");
        }
        catch (HttpRequestException ex)
        {
            _logger.LogInformation($"无法连接到LM Studio服务进行模型检测: {ex.Message}");
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "通过API检测当前模型时发生错误");
        }

        return null;
    }

    /// <summary>
    /// 根据模型名称获取合适的MaxTokens设置
    /// </summary>
    private int GetModelMaxTokens(string modelId)
    {
        // 根据模型名称特征判断合适的token限制
        var modelLower = modelId.ToLower();

        // 大型模型（通常支持更多tokens）
        if (modelLower.Contains("32b") || modelLower.Contains("70b") || modelLower.Contains("qwenlong"))
        {
            return 32768; // 32K tokens，适合长文本生成
        }

        // 中型模型
        if (modelLower.Contains("14b") || modelLower.Contains("20b") || modelLower.Contains("qwen"))
        {
            return 16384; // 16K tokens
        }

        // 小型模型
        if (modelLower.Contains("7b") || modelLower.Contains("8b"))
        {
            return 8192; // 8K tokens
        }

        // 默认设置，适合章节生成
        return 16384;
    }

    public async Task<List<AIModel>> GetAvailableModelsAsync()
    {
        if (!_availableModels.Any())
        {
            await LoadAvailableModelsAsync();
        }

        return _availableModels.ToList();
    }

    /// <summary>
    /// 手动刷新模型列表并检测当前模型
    /// </summary>
    public async Task RefreshModelsAndDetectCurrentAsync()
    {
        _logger.LogInformation("手动刷新LM Studio模型列表...");
        await LoadAvailableModelsAsync();
        await DetectAndSetCurrentModelAsync();
    }

    public async Task<bool> SetCurrentModelAsync(string modelId)
    {
        try
        {
            // 首先确保模型列表已加载
            if (!_availableModels.Any())
            {
                await LoadAvailableModelsAsync();
            }

            var model = _availableModels.FirstOrDefault(m => m.Id == modelId);
            if (model == null)
            {
                // 用户要求：能够主动切换到指定模型，即使不在当前缓存列表中
                _logger.LogWarning($"LM Studio模型未在缓存列表中: {modelId}，将直接设为当前目标模型");
                _currentModel = new AIModel { Id = modelId, Name = modelId, Provider = "LMStudio", IsAvailable = true };
                return true;
            }

            // LM Studio使用OpenAI兼容API，测试连接
            try
            {
                var testRequest = new
                {
                    model = model.Id,
                    messages = new[]
                    {
                        new { role = "user", content = "test" }
                    },
                    max_tokens = 1
                };

                var json = JsonSerializer.Serialize(testRequest);
                var content = new StringContent(json, Encoding.UTF8, "application/json");
                var response = await _httpClient.PostAsync($"{_baseUrl}/v1/chat/completions", content);

                if (response.IsSuccessStatusCode)
                {
                    _currentModel = model;
                    _logger.LogInformation($"切换到LM Studio模型: {model.Name}");
                    return true;
                }
                else
                {
                    _logger.LogWarning($"LM Studio模型测试失败: {model.Id}, 状态码: {response.StatusCode}");
                }
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, $"LM Studio模型连接测试失败: {model.Id}");
            }

            // 如果连接测试失败，但模型存在，仍然设置为当前模型
            _currentModel = model;
            _logger.LogInformation($"设置LM Studio模型（未验证连接）: {model.Name}");
            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"设置LM Studio模型失败: {modelId}");
            return false;
        }
    }

    public AIModel? GetCurrentModel()
    {
        return _currentModel;
    }

    public async Task<string> GenerateTextAsync(string prompt, int maxTokens = 2000, float temperature = 0.7f)
    {
        if (_currentModel == null)
        {
            // 尝试自动加载第一个可用模型
            _logger.LogWarning("当前模型为空，尝试加载第一个可用模型");
            await LoadAvailableModelsAsync();

            if (_availableModels.Any())
            {
                var firstModel = _availableModels.First();
                var success = await SetCurrentModelAsync(firstModel.Id);
                if (!success || _currentModel == null)
                {
                    throw new InvalidOperationException($"请先设置模型，未设置模型LM Studio模型。可用模型: {string.Join(", ", _availableModels.Select(m => m.Id))}");
                }
            }
            else
            {
                throw new InvalidOperationException("请先设置模型，未设置模型LM Studio模型。LM Studio服务未启动或没有加载模型。");
            }
        }

        const int maxRetries = 3;
        var retryDelay = TimeSpan.FromSeconds(2);

        // 检查提示词长度，给出警告
        if (prompt.Length > 8000)
        {
            _logger.LogWarning($"提示词过长({prompt.Length}字符)，可能导致推理失败。建议控制在8000字符以内。");
        }

        // 在第一次尝试前检查模型状态
        if (!await CheckModelStatusAsync())
        {
            _logger.LogWarning("模型状态检查失败，但仍尝试继续生成");
        }

        for (int attempt = 1; attempt <= maxRetries; attempt++)
        {
            try
            {
                _logger.LogInformation($"使用LM Studio模型 {_currentModel.Name} 生成文本，提示词长度: {prompt.Length} (尝试 {attempt}/{maxRetries})");

                var request = new
                {
                    model = _currentModel.Id,
                    messages = new[]
                    {
                        new { role = "user", content = prompt }
                    },
                    max_tokens = Math.Min(maxTokens, _currentModel.MaxTokens),
                    temperature = Math.Max(0.1f, Math.Min(1.0f, temperature)),
                    stream = false
                };

                var json = JsonSerializer.Serialize(request);
                var content = new StringContent(json, Encoding.UTF8, "application/json");

                // 为章节生成设置更长的超时时间
                using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(25)); // 从10分钟增加到25分钟
                var response = await _httpClient.PostAsync($"{_baseUrl}/v1/chat/completions", content, cts.Token);

                if (!response.IsSuccessStatusCode)
                {
                    var errorContent = await response.Content.ReadAsStringAsync();
                    var errorMessage = $"LM Studio API调用失败 (状态码: {response.StatusCode}): {errorContent}";

                    // 解析具体的错误类型并提供针对性建议
                    if (errorContent.Contains("prediction-error"))
                    {
                        var detailedMessage = "LM Studio模型推理失败，可能原因：\n" +
                            "1. 模型资源不足（显存/内存不够）\n" +
                            "2. 输入内容过长，超过模型上下文限制\n" +
                            "3. 模型状态异常或未正确加载\n" +
                            "4. 模型推理过程中遇到内部错误\n\n" +
                            "建议解决方案：\n" +
                            "- 重启LM Studio并重新加载模型\n" +
                            "- 检查显存和内存使用情况\n" +
                            "- 尝试使用较小的模型\n" +
                            "- 减少单次请求的内容长度";

                        _logger.LogError($"LM Studio prediction-error详情: {errorContent}");
                        throw new InvalidOperationException(detailedMessage);
                    }

                    // 如果是服务器错误且还有重试机会，则重试
                    if ((int)response.StatusCode >= 500 && attempt < maxRetries)
                    {
                        _logger.LogWarning($"LM Studio服务器错误，将重试 (尝试 {attempt}/{maxRetries}): {errorMessage}");

                        // 针对BadGateway错误的特殊处理
                        if (response.StatusCode == HttpStatusCode.BadGateway)
                        {
                            _logger.LogInformation("检测到BadGateway错误，可能是模型负载过高，延长等待时间");
                            await Task.Delay(retryDelay * attempt * 2); // 延长等待时间
                        }
                        else
                        {
                            await Task.Delay(retryDelay * attempt);
                        }
                        continue;
                    }

                    throw new HttpRequestException(errorMessage);
                }

                var responseJson = await response.Content.ReadAsStringAsync();
                var result = JsonSerializer.Deserialize<LMStudioResponse>(responseJson);

                if (result?.Choices?.Length > 0)
                {
                    var generatedText = result.Choices[0].Message.Content ?? "";
                    _logger.LogInformation($"LM Studio文本生成成功，生成长度: {generatedText.Length}");
                    return generatedText;
                }

                throw new InvalidOperationException("LM Studio返回空响应");
            }
            catch (TaskCanceledException ex) when (ex.InnerException is TimeoutException)
            {
                _logger.LogWarning($"LM Studio请求超时 (尝试 {attempt}/{maxRetries})");
                if (attempt == maxRetries)
                {
                    throw new TimeoutException($"LM Studio请求超时，已重试 {maxRetries} 次");
                }
            }
            catch (HttpRequestException ex) when (attempt < maxRetries)
            {
                _logger.LogWarning($"LM Studio网络请求失败 (尝试 {attempt}/{maxRetries}): {ex.Message}");
                await Task.Delay(retryDelay * attempt);
                continue;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"LM Studio文本生成失败，模型: {_currentModel?.Name} (尝试 {attempt}/{maxRetries})");
                if (attempt == maxRetries)
                {
                    throw new InvalidOperationException($"LM Studio文本生成失败: {ex.Message}", ex);
                }
                await Task.Delay(retryDelay * attempt);
            }
        }

        throw new InvalidOperationException("LM Studio文本生成失败，已达到最大重试次数");
    }

    /// <summary>
    /// 检查当前模型状态是否正常
    /// </summary>
    private async Task<bool> CheckModelStatusAsync()
    {
        try
        {
            if (_currentModel == null)
                return false;

            var response = await _httpClient.GetAsync($"{_baseUrl}/v1/models");
            if (response.IsSuccessStatusCode)
            {
                var content = await response.Content.ReadAsStringAsync();
                // 检查当前模型是否在可用模型列表中
                var isModelAvailable = content.Contains(_currentModel.Id);

                if (!isModelAvailable)
                {
                    _logger.LogWarning($"当前模型 {_currentModel.Id} 不在可用模型列表中");
                }

                return isModelAvailable;
            }
            else
            {
                _logger.LogWarning($"检查模型状态失败，状态码: {response.StatusCode}");
                return false;
            }
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "检查模型状态时发生异常");
            return false;
        }
    }

    /// <summary>
    /// 带降级机制的文本生成方法
    /// </summary>
    public async Task<string> GenerateTextWithFallbackAsync(string prompt, int maxTokens = 2000, float temperature = 0.7f)
    {
        try
        {
            // 尝试完整生成
            return await GenerateTextAsync(prompt, maxTokens, temperature);
        }
        catch (Exception ex) when (ex.Message.Contains("prediction-error") || ex.Message.Contains("推理失败"))
        {
            _logger.LogWarning("完整生成失败，尝试降级生成");

            try
            {
                // 降级方案1：减少token数量
                var reducedTokens = Math.Max(maxTokens / 2, 500);
                _logger.LogInformation($"尝试降级生成，token数量从 {maxTokens} 减少到 {reducedTokens}");
                return await GenerateTextAsync(prompt, reducedTokens, temperature);
            }
            catch (Exception ex2)
            {
                _logger.LogWarning($"降级生成也失败: {ex2.Message}");

                // 降级方案2：简化提示词
                var simplifiedPrompt = SimplifyPrompt(prompt);
                var minTokens = Math.Max(maxTokens / 4, 200);
                _logger.LogInformation($"尝试简化提示词生成，token数量: {minTokens}");
                return await GenerateTextAsync(simplifiedPrompt, minTokens, 0.5f);
            }
        }
    }

    /// <summary>
    /// 简化提示词，保留核心内容
    /// </summary>
    private string SimplifyPrompt(string originalPrompt)
    {
        // 如果提示词过长，保留前半部分和最后的要求
        if (originalPrompt.Length > 2000)
        {
            var lines = originalPrompt.Split('\n');
            var coreLines = lines.Take(lines.Length / 2).ToList();

            // 添加简化的生成要求
            coreLines.Add("\n请根据以上信息生成相关内容。");

            var simplified = string.Join("\n", coreLines);
            _logger.LogInformation($"提示词已简化，从 {originalPrompt.Length} 字符减少到 {simplified.Length} 字符");
            return simplified;
        }

        return originalPrompt;
    }

    public async Task<string> PolishTextAsync(string text, string style = "通用")
    {
        var prompt = $@"请对以下文本进行润色，要求：
1. 保持原文的核心意思不变
2. 提升文字的流畅性和可读性
3. 润色风格：{style}
4. 只返回润色后的文本，不要添加任何解释

原文：
{text}";

        return await GenerateTextAsync(prompt, 4000, 0.3f);
    }

    public async Task<string> ExpandTextAsync(string text, int targetLength, string? context = null)
    {
        var contextInfo = !string.IsNullOrEmpty(context) ? $"\n\n上下文信息：\n{context}" : "";
        
        var prompt = $@"请对以下文本进行扩写，要求：
1. 保持原文的核心内容和风格
2. 增加细节描述、情感表达和场景渲染
3. 目标长度约{targetLength}字
4. 确保扩写内容与原文自然衔接
5. 只返回扩写后的完整文本{contextInfo}

原文：
{text}";

        return await GenerateTextAsync(prompt, Math.Max(targetLength + 1000, 4000), 0.7f);
    }

    public async Task<string> GenerateChapterAsync(string outline, string? context = null, int targetWordCount = 6500)
    {
        var contextInfo = !string.IsNullOrEmpty(context) ? $"\n\n上下文信息：\n{context}" : "";
        
        var prompt = $@"请根据以下章节大纲创作小说章节内容。

=== 章节大纲 ===
{outline}

=== 字数要求（必须严格遵守）===
**目标字数：{targetWordCount}字**
- 最少不能低于{(int)(targetWordCount * 0.9)}字
- 最多不能超过{(int)(targetWordCount * 1.1)}字
- 请在创作过程中时刻关注字数，确保达到目标字数
- 如果内容不够，请增加细节描写、心理描写、环境描写等
- 如果内容过多，请适当精简，但不能删除关键情节

=== 创作要求 ===
1. 严格按照大纲内容进行创作
2. **必须达到{targetWordCount}字的目标字数，这是硬性要求**
3. 保持小说的连贯性和可读性
4. 注意人物性格和情节发展的一致性
5. 只返回章节正文内容，不要标题和其他说明
6. **在创作时要充分展开情节，增加对话、动作、心理、环境等描写来达到字数要求**{contextInfo}

=== 创作指导 ===
为了达到{targetWordCount}字的要求，请注意：
- 详细描写人物的外貌、表情、动作
- 丰富环境和场景的描述
- 增加人物内心独白和心理活动
- 扩展对话内容，让对话更自然生动
- 添加适当的背景信息和回忆片段
- 细致描写战斗、冲突等关键场面";

        try
        {
            // 计算合适的token数量（中文字符约1.5倍token）
            var estimatedTokens = (int)(targetWordCount * 1.5) + 2000;
            var maxTokens = Math.Min(estimatedTokens, _currentModel?.MaxTokens ?? 16384);

            _logger.LogInformation($"章节生成参数：目标字数={targetWordCount}，估算tokens={estimatedTokens}，实际使用={maxTokens}");

            // 首先尝试正常生成
            return await GenerateTextAsync(prompt, maxTokens, 0.8f);
        }
        catch (Exception ex) when (ex.Message.Contains("prediction-error") || ex.Message.Contains("推理失败") || ex.Message.Contains("BadGateway"))
        {
            _logger.LogWarning($"章节生成失败，尝试降级生成: {ex.Message}");

            // 使用降级机制
            return await GenerateTextWithFallbackAsync(prompt, Math.Max(targetWordCount + 1000, 4000), 0.8f);
        }
    }

    public async Task<ConsistencyCheckResult> CheckConsistencyAsync(string currentText, string previousContext)
    {
        var prompt = $@"请检查以下当前文本与之前上下文的一致性，重点关注：
1. 人物性格和行为是否一致
2. 情节发展是否合理
3. 时间线是否正确
4. 设定是否矛盾

请分析并给出结果，包括是否一致、置信度评分(0-1)、发现的问题和改进建议。

之前的上下文：
{previousContext}

当前文本：
{currentText}";

        try
        {
            var response = await GenerateTextAsync(prompt, 2000, 0.3f);
            
            // 解析响应文本
            var isConsistent = !response.ToLower().Contains("不一致") && 
                              !response.ToLower().Contains("矛盾") && 
                              !response.ToLower().Contains("inconsistent");
            
            var confidenceScore = ExtractConfidenceScore(response);
            
            return new ConsistencyCheckResult
            {
                IsConsistent = isConsistent,
                ConfidenceScore = confidenceScore,
                Issues = ExtractIssues(response),
                Suggestions = ExtractSuggestions(response)
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "LM Studio一致性检查失败");
            return new ConsistencyCheckResult
            {
                IsConsistent = false,
                ConfidenceScore = 0.0f,
                Issues = new List<string> { $"检查过程出错: {ex.Message}" },
                Suggestions = new List<string> { "建议重新进行一致性检查" }
            };
        }
    }

    private float ExtractConfidenceScore(string response)
    {
        // 查找数字评分
        var lines = response.Split('\n');
        foreach (var line in lines)
        {
            if (line.Contains("置信度") || line.Contains("评分") || line.Contains("confidence"))
            {
                var numbers = System.Text.RegularExpressions.Regex.Matches(line, @"0\.\d+|\d+\.\d+");
                if (numbers.Count > 0)
                {
                    if (float.TryParse(numbers[0].Value, out var score))
                    {
                        return Math.Max(0.0f, Math.Min(1.0f, score));
                    }
                }
            }
        }
        
        // 基于关键词的评分
        if (response.Contains("很好") || response.Contains("完全一致"))
            return 0.9f;
        if (response.Contains("基本一致") || response.Contains("大体"))
            return 0.7f;
        if (response.Contains("部分") || response.Contains("轻微"))
            return 0.5f;
        if (response.Contains("不一致") || response.Contains("矛盾"))
            return 0.3f;
        
        return 0.6f;
    }

    private List<string> ExtractIssues(string response)
    {
        var issues = new List<string>();
        var lines = response.Split('\n');
        
        foreach (var line in lines)
        {
            if (line.Contains("问题") || line.Contains("矛盾") || line.Contains("不一致") || 
                line.Contains("issue") || line.Contains("problem"))
            {
                issues.Add(line.Trim());
            }
        }
        
        return issues.Any() ? issues : new List<string> { "未发现明显问题" };
    }

    private List<string> ExtractSuggestions(string response)
    {
        var suggestions = new List<string>();
        var lines = response.Split('\n');
        
        foreach (var line in lines)
        {
            if (line.Contains("建议") || line.Contains("应该") || line.Contains("可以") || 
                line.Contains("suggest") || line.Contains("recommend"))
            {
                suggestions.Add(line.Trim());
            }
        }
        
        return suggestions.Any() ? suggestions : new List<string> { "保持当前写作方向" };
    }

    public async Task<string> GenerateOutlineAsync(string description, string outlineType)
    {
        var prompt = outlineType.ToLower() switch
        {
            "全书" => $@"请根据以下描述生成小说全书大纲，要求：
1. 包含主要情节线和人物关系
2. 分为若干卷或部分
3. 每部分包含主要事件和发展
4. 保持情节的连贯性和吸引力

描述：{description}",

            "卷宗" => $@"请根据以下描述生成卷宗大纲，要求：
1. 详细的章节安排
2. 每章的主要内容和目标
3. 人物发展和情节推进
4. 保持节奏感和悬念

描述：{description}",

            "章节" => $@"请根据以下描述生成章节细纲，要求：
1. 详细的场景安排
2. 人物对话和行动
3. 情节发展的关键点
4. 字数约6500字的内容规划

描述：{description}",

            _ => $@"请根据以下描述生成{outlineType}大纲：

描述：{description}"
        };

        return await GenerateTextAsync(prompt, 4000, 0.8f);
    }

    public async Task<List<CharacterInfo>> ExtractCharacterInfoAsync(string text)
    {
        var prompt = $@"请从以下文本中提取角色信息，包括：
- 角色名称
- 角色描述
- 角色属性（如境界、年龄等）
- 技能列表
- 装备列表

请按以下格式输出每个角色：
角色名：[名称]
描述：[描述]
属性：[属性1]=[值1], [属性2]=[值2]
技能：[技能1], [技能2]
装备：[装备1], [装备2]

文本内容：
{text}";

        try
        {
            var response = await GenerateTextAsync(prompt, 3000, 0.3f);
            return ParseCharacterInfo(response);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "LM Studio角色信息提取失败");
            return new List<CharacterInfo>();
        }
    }

    private List<CharacterInfo> ParseCharacterInfo(string response)
    {
        var characters = new List<CharacterInfo>();
        var lines = response.Split('\n');
        CharacterInfo? currentCharacter = null;

        foreach (var line in lines)
        {
            var trimmedLine = line.Trim();

            if (trimmedLine.StartsWith("角色名：") || trimmedLine.StartsWith("角色名:"))
            {
                if (currentCharacter != null)
                {
                    characters.Add(currentCharacter);
                }

                currentCharacter = new CharacterInfo
                {
                    Name = trimmedLine.Substring(trimmedLine.IndexOf('：') + 1).Trim()
                };
                if (string.IsNullOrEmpty(currentCharacter.Name))
                {
                    currentCharacter.Name = trimmedLine.Substring(trimmedLine.IndexOf(':') + 1).Trim();
                }
            }
            else if (currentCharacter != null)
            {
                if (trimmedLine.StartsWith("描述：") || trimmedLine.StartsWith("描述:"))
                {
                    currentCharacter.Description = trimmedLine.Substring(trimmedLine.IndexOf('：') + 1).Trim();
                    if (string.IsNullOrEmpty(currentCharacter.Description))
                    {
                        currentCharacter.Description = trimmedLine.Substring(trimmedLine.IndexOf(':') + 1).Trim();
                    }
                }
                else if (trimmedLine.StartsWith("属性：") || trimmedLine.StartsWith("属性:"))
                {
                    var attributesStr = trimmedLine.Substring(trimmedLine.IndexOf('：') + 1).Trim();
                    if (string.IsNullOrEmpty(attributesStr))
                    {
                        attributesStr = trimmedLine.Substring(trimmedLine.IndexOf(':') + 1).Trim();
                    }

                    var attributes = attributesStr.Split(',');
                    foreach (var attr in attributes)
                    {
                        var parts = attr.Split('=');
                        if (parts.Length == 2)
                        {
                            currentCharacter.Attributes[parts[0].Trim()] = parts[1].Trim();
                        }
                    }
                }
                else if (trimmedLine.StartsWith("技能：") || trimmedLine.StartsWith("技能:"))
                {
                    var skillsStr = trimmedLine.Substring(trimmedLine.IndexOf('：') + 1).Trim();
                    if (string.IsNullOrEmpty(skillsStr))
                    {
                        skillsStr = trimmedLine.Substring(trimmedLine.IndexOf(':') + 1).Trim();
                    }

                    var skills = skillsStr.Split(',');
                    currentCharacter.Skills.AddRange(skills.Select(s => s.Trim()).Where(s => !string.IsNullOrEmpty(s)));
                }
                else if (trimmedLine.StartsWith("装备：") || trimmedLine.StartsWith("装备:"))
                {
                    var equipmentStr = trimmedLine.Substring(trimmedLine.IndexOf('：') + 1).Trim();
                    if (string.IsNullOrEmpty(equipmentStr))
                    {
                        equipmentStr = trimmedLine.Substring(trimmedLine.IndexOf(':') + 1).Trim();
                    }

                    var equipment = equipmentStr.Split(',');
                    currentCharacter.Equipment.AddRange(equipment.Select(e => e.Trim()).Where(e => !string.IsNullOrEmpty(e)));
                }
            }
        }

        if (currentCharacter != null)
        {
            characters.Add(currentCharacter);
        }

        return characters;
    }

    public async Task<string> TranslateTextAsync(string text, string sourceLanguage, string targetLanguage)
    {
        var prompt = $@"请将以下{sourceLanguage}文本翻译为{targetLanguage}，要求：
1. 保持原文的意思和语调
2. 使用自然流畅的{targetLanguage}表达
3. 只返回翻译结果，不要添加任何解释

原文：
{text}";

        return await GenerateTextAsync(prompt, text.Length * 2, 0.3f);
    }

    public async Task<string> SummarizeTextAsync(string text, int maxLength = 500)
    {
        var prompt = $@"请对以下文本进行总结，要求：
1. 总结长度不超过{maxLength}字
2. 保留核心要点和关键信息
3. 语言简洁明了
4. 只返回总结内容，不要添加任何解释

原文：
{text}";

        return await GenerateTextAsync(prompt, maxLength + 200, 0.5f);
    }

    public async Task<string> ContinueWritingAsync(string context, int targetLength = 500)
    {
        var prompt = $@"请基于以下上下文继续写作，要求：
1. 续写长度约{targetLength}字
2. 保持与上下文的风格一致
3. 内容连贯自然
4. 只返回续写内容，不要添加任何解释

上下文：
{context}";

        return await GenerateTextAsync(prompt, targetLength + 300, 0.8f);
    }
}



/// <summary>
/// LM Studio聊天响应
/// </summary>
public class LMStudioResponse
{
    [JsonPropertyName("choices")]
    public LMStudioChoice[]? Choices { get; set; }
}

public class LMStudioChoice
{
    [JsonPropertyName("message")]
    public LMStudioMessage Message { get; set; } = new();
}

public class LMStudioMessage
{
    [JsonPropertyName("content")]
    public string? Content { get; set; }
}
